package at.theengine.android.botstorage;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;  
import org.apache.http.client.HttpClient;   
import org.apache.http.client.methods.HttpGet;  
import org.apache.http.impl.client.DefaultHttpClient; 
import org.xml.sax.SAXException;

import android.R.xml;
import android.content.Context;
import android.util.Log;
import at.theengine.android.botstorage.gsobjects.Bucket;
import at.theengine.android.botstorage.gsobjects.GsObject;
import at.theengine.android.botstorage.gsobjects.GsObjects;
import at.theengine.android.botstorage.gsobjects.GsObject.ObjectType;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.ParserConfigurationException;

public class StorageService {
	
	//android specific objects
	private static final String TAG = "BotStorage";
	private Context ctx; //TODO use this

	private static final String HTTP = "http://";
	private static final String HTTPS = "https://";
	public static String ENDPOINT = "commondatastorage.googleapis.com";  
    
	//Google Auth
	private String key;
	private String secret;
	
	//connection objects
	private HttpClient client;
	
	//setting key an secret for auth
	public StorageService(String key,String secret){
		this.key = key;
		this.secret = secret;
	}
	
	public Bucket[] getBuckets() throws BotStorageException{  
        //build request
		client = new DefaultHttpClient();
		
		HttpGet request;
		try { 
			request = buildGetRequest(ENDPOINT, "/","","");
		} catch (Exception e) {
            Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
        }
		
        HttpResponse response; 
        
        String bucketsXML;
        
        //execute Request
        try {  
            response = client.execute(request);
            byte[] b = new byte[(int) response.getEntity().getContentLength()];
            int i = response.getEntity().getContent().read(b,0,(int) response.getEntity().getContentLength());
            bucketsXML = new String(b);
        } catch (Exception e) {  
        	bucketsXML = "";
            Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
        }
        
        client.getConnectionManager().shutdown();  
        client = null;
        
        Bucket[] buckets;
        
        //Create Bucket Objects
        try {
			buckets = GsObjectBuilder.buildBucketObjects(bucketsXML);
		} catch (SAXException e) {
			Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
		} catch (IOException e) {
			Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
		} catch (ParserConfigurationException e) {
			Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
		}
        
        return buckets;
    } 
	
	public GsObjects getGsObjects(String bucket,String path) throws BotStorageException{  
        //build request
		client = new DefaultHttpClient();
		
		HttpGet request;
		try { 
			request = buildGetRequest(ENDPOINT, "/" + bucket,"?delimiter=/&prefix=" + path,"");
		} catch (Exception e) {
            Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
        }
		
        HttpResponse response; 
        
        String objectXml;
        
        //execute Request
        try {  
            response = client.execute(request);
            byte[] b = new byte[(int) response.getEntity().getContentLength()];
            int i = response.getEntity().getContent().read(b,0,(int) response.getEntity().getContentLength());
            objectXml = new String(b);
        } catch (Exception e) {  
        	objectXml = "";
            Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
        }
        
        client.getConnectionManager().shutdown();  
        client = null;
        
        GsObjects gsObjects;
        
        //Create Bucket Objects
        try {
        	gsObjects = GsObjectBuilder.buildGsObjects(objectXml);
		} catch (SAXException e) {
			Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
		} catch (IOException e) {
			Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
		} catch (ParserConfigurationException e) {
			Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
		}
        
        return gsObjects;
    }
	
	public InputStream downloadGsFile(String bucket,String path) throws BotStorageException{  
        //build request
		client = new DefaultHttpClient();
		
		HttpGet request;
		try { 
			request = buildGetRequest(bucket.substring(0,bucket.length()-1) + "." + ENDPOINT,path,"","/" + bucket.substring(0,bucket.length()-1));
		} catch (Exception e) {
            Log.e(TAG,e.getMessage());
            throw new BotStorageException(e.getMessage());
        }
		
        HttpResponse response; 
        
        InputStream data;
        
        //execute Request
        try {  
            response = client.execute(request);
            data = response.getEntity().getContent();
        } catch (Exception e) {
            throw new BotStorageException(e.getMessage());
        }
        return data;
    }
  
    private HttpGet buildGetRequest(String host,String path,String queryString,String bucket) throws Exception{
    	HttpGet request;
    	request = new HttpGet(HTTP + host + path + queryString);
    	
    	try {
    	//build date 
    	Date d = new Date();
		SimpleDateFormat dateFormatGmt = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");
		dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
		String date = dateFormatGmt.format(d);
    	
        request.addHeader("Host", host); 
        request.addHeader("Date", date); 
        String auth = "GOOG1 " + key + ":" + getSignature("GET",host,date,"","",bucket + path);
        request.addHeader("Authorization", auth); 
        request.addHeader("Content-Length","0");
        
        Log.i(TAG,"HTTP GET REQUEST:" + host + "," + String.valueOf(date) + "," + auth + "," + "0");

	    } catch (Exception e) {
	    	Log.e(TAG,e.getMessage());
	    	throw e;
	    }
        
    	return request;
    }
    
    private String getSignature(String method,String host,String date,String contentType,String extensionHeaders,String path) throws Exception{
    	String msg = getMsgTobeSigned(method,host,date,contentType,extensionHeaders,path);
    	
    	String signed = "";
    	try {
    		// get an hmac_sha1 key from the raw key bytes
    		SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), "HmacSHA1");

    		// get an hmac_sha1 Mac instance and initialize with the signing key
    		Mac mac = Mac.getInstance("HmacSHA1");
    		mac.init(signingKey);

    		// compute the hmac on input data bytes
    		byte[] rawHmac = mac.doFinal(msg.getBytes());

    		// base64-encode the hmac
    		signed = Base64.encodeBytes(rawHmac, 0, rawHmac.length);

    		} catch (Exception e) {
    			Log.e(TAG,e.getMessage());
    			throw e;
    		}
    		
	  return signed;
    }
    
    private String getMsgTobeSigned(String method,String host,String date,String contentType,String extensionHeaders,String path){
    	StringBuilder sbMsg = new StringBuilder();
    	
    	//Start with method
    	sbMsg.append(method);
    	sbMsg.append("\n");
    	
    	//TODO: check what this empty line is for
    	sbMsg.append("\n");
    	
    	//content type
    	sbMsg.append(contentType);
    	sbMsg.append("\n");
    	
    	//content type
    	sbMsg.append(date);
    	sbMsg.append("\n");
    	
    	//content type
    	sbMsg.append(extensionHeaders);
    	
    	//path
    	sbMsg.append(path);
    	
    	return sbMsg.toString();
    }
    
    
    
    
    
//    public void Test(String key, String secret){  
//        HttpClient client = new DefaultHttpClient();
//        
//        HttpGet request = new HttpGet(HTTP + ENDPOINT); 
//        Date d = new Date();
//    	SimpleDateFormat  sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");
//    	String date = sdf.format(d);
//        request.addHeader("Host", ENDPOINT); 
//        request.addHeader("Date", date); 
//        String auth = "GOOG1 " + key + ":" + getSignature(date,secret);
//        request.addHeader("Authorization", auth); 
//        request.addHeader("Content-Length","0");
//        
//        HttpResponse response; 
//        try {  
//            response = client.execute(request);  
//            response.toString();
//            byte[] b = new byte[(int) response.getEntity().getContentLength()];
//            int i = response.getEntity().getContent().read(b,0,(int) response.getEntity().getContentLength());
//            String s = new String(b);
//            Log.i("HALLO!",s);
//        } catch (ClientProtocolException e) {  
//            e.printStackTrace();  
//        } catch (IOException e) {  
//            e.printStackTrace();  
//        }  
//        client.getConnectionManager().shutdown();  
//    } 
//    
//    private String getSignature(String date,String secret){
//    	
//    	String message = "GET\n\n\n" + date + "\n" + "/";
//    	String signed = "";
//    	
//    	try {
//
//    		// get an hmac_sha1 key from the raw key bytes
//    		SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), "HmacSHA1");
//
//    		// get an hmac_sha1 Mac instance and initialize with the signing key
//    		Mac mac = Mac.getInstance("HmacSHA1");
//    		mac.init(signingKey);
//
//    		// compute the hmac on input data bytes
//    		byte[] rawHmac = mac.doFinal(message.getBytes());
//
//    		// base64-encode the hmac
//    		signed = Base64.encodeBytes(rawHmac, 0, rawHmac.length);
//
//    		} catch (Exception e) {
//    		
//    		}
//	  
//	  return signed;
//    }
	
	

}

